package ldh.serialize.util;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.codec.Charsets;
import org.apache.commons.codec.binary.Base64;

public class TransferUtil {

	public static byte[] varIntToBytes(int num) {
		return CompressionUtil.intToByte(num);
	}
	
	public static byte[] intToBytes(int num) {
		byte[] i32out = new byte[4];
		i32out[3] = (byte)(0xff & (num >> 24));
	    i32out[2] = (byte)(0xff & (num >> 16));
	    i32out[1] = (byte)(0xff & (num >> 8));
	    i32out[0] = (byte)(0xff & (num));
	    return i32out;
	}
	
	public static byte[] shortToBytes(short num) {
		byte[] i32out = new byte[2];
	    i32out[0] = (byte)(0xff & (num >> 8));
	    i32out[1] = (byte)(0xff & (num));
	    return i32out;
	}
	
	public static short bytesToShort(byte[] bytes, int start) {
		return (short)(
        ((bytes[start + 0] & 0xff) <<  8) |
        ((bytes[start + 1] & 0xff)));
	}
	
	public static int bytesToInt(byte[] bytes, int start) {
		return ((bytes[start + 3] & 0xff) << 24) |
        ((bytes[start + 2] & 0xff) << 16) |
        ((bytes[start + 1] & 0xff) <<  8) |
        ((bytes[start + 0] & 0xff));
	}
	
	public static byte[] longToBytes(Long num) {
		byte[] bytes = new byte[8];
        bytes[0] = (byte) (num & 0xff);
        bytes[1] = (byte) ((num >> 8) & 0xff);
        bytes[2] = (byte) ((num >> 16) & 0xff);
        bytes[3] = (byte) ((num >> 24) & 0xff);
        bytes[4] = (byte) ((num >> 32) & 0xff);
        bytes[5] = (byte) ((num >> 40) & 0xff);
        bytes[6] = (byte) ((num >> 48) & 0xff);
        bytes[7] = (byte) ((num >> 56) & 0xff);
        return bytes;
	}
	
	public static long bytesToLong(byte[] bytes, int start) {
		return  (0xffL & (long)bytes[start + 0]) | 
				(0xff00L & ((long)bytes[start + 1] << 8)) | 
				(0xff0000L & ((long)bytes[start + 2] << 16)) | 
				(0xff000000L & ((long)bytes[start + 3] << 24))| 
				(0xff00000000L & ((long)bytes[start + 4] << 32)) | 
				(0xff0000000000L & ((long)bytes[start + 5] << 40)) | 
				(0xff000000000000L & ((long)bytes[start + 6] << 48)) | 
				(0xff00000000000000L & ((long)bytes[start + 7] << 56));
	}
	
	public static Byte[] toBytes(byte[] bytes) {
		Byte[] bb = new Byte[bytes.length];
		System.arraycopy(bytes, 0, bb, 0, bytes.length);
		return bb;
	}
	
	public static byte[] toBytes(Byte[] bytes) {
		byte[] bb = new byte[bytes.length];
		System.arraycopy(bytes, 0, bb, 0, bytes.length);
		return bb;
	}
	
	public static String toString(byte[] bytes) {
		return Base64.encodeBase64String(bytes);
	}
	
	public static byte[] toBytes(String str) {
		return Base64.decodeBase64(str.getBytes(Charsets.UTF_8));
	}
	
	static Map<Class<?>, Class<?>> clazzs = new HashMap<Class<?>, Class<?>>();
	static {
		clazzs.put(int.class, Integer.class);
		clazzs.put(short.class, Short.class);
		clazzs.put(byte.class, Byte.class);
		clazzs.put(float.class, Float.class);
		clazzs.put(double.class, Double.class);
		clazzs.put(long.class, Long.class);
	}
	
	public static Class<?> convert(Class<?> clazz) {
		return clazzs.get(clazz);
	}
	
	public static Class<?> getIterableParam(Type type) {
		if (type instanceof ParameterizedType) {
			ParameterizedType parameterizedType = (ParameterizedType)type;
            Type basicType = parameterizedType.getRawType();   
            Type[] types = parameterizedType.getActualTypeArguments();   
            Class<?> key = (Class<?>) types[0];
            return key;
		}
		return null;
	}
	
	public static Class<?>[] getMapParam(Type type) {
		if (type instanceof ParameterizedType) {
			ParameterizedType parameterizedType = (ParameterizedType)type;
            Type basicType = parameterizedType.getRawType();   
            Type[] types = parameterizedType.getActualTypeArguments();   
            return new Class<?>[] {(Class<?>) types[0], (Class<?>) types[1]};
		}
		return null;
	}
}
